﻿using System;
using System.Collections.Generic;
using System.Linq;
using IterationLife.ContentResources.Enums;
using IterationLife.ContentResources.Models;
using IterationLife.ContentResources.Repositories;
using IterationLife.Extensions.Dtos;
using IterationLife.Extensions.Enums;
using IterationLife.Mobile.AppServices.Dtos.Common;
using Util;

namespace IterationLife.Mobile.AppServices.Services.Common.Implements
{
    /// <summary>
    /// 内容资源服务
    /// </summary>
    public class ContentResourceService : IContentResourceService
    {
        /// <summary>
        /// 内容资源分类仓储
        /// </summary>
        private readonly IContentResourceCategoryRepository _categoryRepository;

        /// <summary>
        /// 内容资源仓储
        /// </summary>
        private readonly IContentResourceRepository _contentRepository;

        /// <summary>
        /// 内容资源评论仓储
        /// </summary>
        private readonly IContentResourceCommentRepository _commentRepository;

        /// <summary>
        /// 初始化内容资源服务
        /// </summary>
        /// <param name="categoryRepository">内容资源分类仓储</param>
        /// <param name="contentRepository">内容资源仓储</param>
        /// <param name="commentRepository">内容资源评论仓储</param>
        public ContentResourceService(
            IContentResourceCategoryRepository categoryRepository,
            IContentResourceRepository contentRepository,
            IContentResourceCommentRepository commentRepository
            )
        {
            _categoryRepository = categoryRepository;
            _contentRepository = contentRepository;
            _commentRepository = commentRepository;
        }

        /// <summary>
        /// 热点内容资源列表
        /// </summary>
        /// <param name="size">条数</param>
        /// <param name="codes">分类编码集合</param>
        /// <param name="tags">标签集合</param>
        public List<ContentResourceListOutPut> HotList(int size, string codes = null, string tags = null)
        {
            var categoryIds = GetCategoryIdsByCodes(codes);
            var resources = GetResources(size, categoryIds, tags);
            return GetResourceListOutPut(resources);
        }

        /// <summary>
        /// 内容资源范围列表
        /// </summary>
        /// <param name="size">条数</param>
        /// <param name="codes">分类编码集合</param>
        /// <param name="tags">标签集合</param>
        /// <param name="id">内容资源编号</param>
        /// <param name="queryType">查询类型</param>
        public RangeData<ContentResourceListOutPut> RangeList(int size, string codes = null, string tags = null, Guid? id = null, RangeQueryType queryType = RangeQueryType.After)
        {
            var categoryIds = GetCategoryIdsByCodes(codes);
            var resources = GetResources(size, categoryIds, tags, id, queryType);
            if (resources.Count == 0)
                resources = GetAlternateResources(size, categoryIds, tags);
            var result = GetResourceListOutPut(resources);
            return result.Count == 0
                   ? new RangeData<ContentResourceListOutPut>()
                   : new RangeData<ContentResourceListOutPut>(result, result[result.Count - 1].Id.ToString(), result[0].Id.ToString());
        }

        /// <summary>
        /// 根据编码集合获取分类编号集合
        /// </summary>
        /// <param name="codes">编码集合</param>
        private List<Guid?> GetCategoryIdsByCodes(string codes)
        {
            if (codes.IsEmpty())
                return new List<Guid?>();
            return _categoryRepository.GetEnabledIdsByCodes(codes);
        }

        #region 获取资源

        /// <summary>
        /// 获取资源
        /// </summary>
        /// <param name="size">条数</param>
        /// <param name="categoryIds">分类编号集合</param>
        /// <param name="tags">标签集合</param>
        /// <param name="id">当前资源编号</param>
        /// <param name="queryType">查询类型</param>
        private List<ContentResource> GetResources(int size, List<Guid?> categoryIds, string tags, Guid? id = null, RangeQueryType queryType = RangeQueryType.After)
        {
            //正式代码
            //var queryable = _contentRepository.Find();
            //queryable = BaseQueryCondition(queryable);
            //queryable = CodesQueryCondition(queryable, categoryIds);
            //queryable = TagsQueryCondition(queryable, tags);
            //queryable = ResourceIdQueryCondition(queryable, id, queryType);
            //queryable = TakeQueryCondition(queryable, size);
            //return queryable.ToList();


            //临时代码 - 随机取资源


            var queryable = _contentRepository.Find();
            queryable = BaseQueryCondition(queryable);
            queryable = CodesQueryCondition(queryable, categoryIds);
            queryable = TagsQueryCondition(queryable, tags);
            var entities = queryable.ToList();
            if (entities.Count <= size)
                return entities;
            var result = new List<ContentResource>();
            var rm = new Random(Guid.NewGuid().GetHashCode());
            var i = rm.Next(entities.Count - size);
            for (var j = 0; j < size; j++)
            {
                result.Add(entities[i]);
                i++;
            }
            return result.OrderBy(x => Guid.NewGuid()).ToList();
        }

        /// <summary>
        /// 基础查询条件
        /// </summary>
        /// <param name="queryable">查询对象</param>
        private IQueryable<ContentResource> BaseQueryCondition(IQueryable<ContentResource> queryable)
        {
            return queryable.Where(t => t.PublicationTime <= DateTime.Now && t.State == ContentResourceState.Publish);
        }

        /// <summary>
        /// 编码查询条件
        /// </summary>
        /// <param name="queryable">查询对象</param>
        /// <param name="categoryIds">分类编号集合</param>
        private IQueryable<ContentResource> CodesQueryCondition(IQueryable<ContentResource> queryable, List<Guid?> categoryIds)
        {
            if (categoryIds.Count == 0)
                return queryable;
            return queryable.Where(t => categoryIds.Contains(t.CategoriyId));
        }

        /// <summary>
        /// 标签查询条件
        /// </summary>
        /// <param name="queryable">查询对象</param>
        /// <param name="tags">标签集合</param>
        private IQueryable<ContentResource> TagsQueryCondition(IQueryable<ContentResource> queryable, string tags)
        {
            if (tags.IsEmpty())
                return queryable;
            var tagList = Util.Helpers.Convert.ToList<string>(tags).Distinct().ToList();
            foreach (var tag in tagList)
                queryable = queryable.Where(t => t.Tags.Contains(tag));
            return queryable;
        }

        /// <summary>
        /// 资源编号查询条件
        /// </summary>
        /// <param name="queryable">查询对象</param>
        /// <param name="id">资源编号</param>
        /// <param name="queryType">查询类型</param>
        private IQueryable<ContentResource> ResourceIdQueryCondition(IQueryable<ContentResource> queryable, Guid? id, RangeQueryType queryType)
        {
            if (id.IsEmpty())
                return queryable;
            var nowEntity = _contentRepository.Find(id);
            if (queryType == RangeQueryType.After)
                return queryable.Where(t => t.PublicationTime < nowEntity.PublicationTime);
            return queryable.Where(t => t.PublicationTime > nowEntity.PublicationTime);
        }

        /// <summary>
        /// 获取片段查询条件
        /// </summary>
        /// <param name="queryable">查询对象</param>
        /// <param name="size">条数</param>
        private IQueryable<ContentResource> TakeQueryCondition(IQueryable<ContentResource> queryable, int size)
        {
            return queryable.OrderByDescending(t => t.PublicationTime).Take(size).Skip(0);
        }

        #endregion

        #region 获取替补资源

        /// <summary>
        /// 获取替补资源
        /// </summary>
        /// <param name="size">条数</param>
        /// <param name="categoryIds">分类编号集合</param>
        /// <param name="tags">标签集合</param>
        private List<ContentResource> GetAlternateResources(int size, List<Guid?> categoryIds, string tags)
        {
            var queryable = _contentRepository.Find();
            queryable = BaseQueryCondition(queryable);
            queryable = CodesQueryCondition(queryable, categoryIds);
            queryable = TagsQueryCondition(queryable, tags);
            queryable = AlternateQueryCondition(queryable);
            queryable = TakeQueryCondition(queryable, size);
            return queryable.ToList();
        }

        /// <summary>
        /// 替补查询条件
        /// </summary>
        /// <param name="queryable">查询对象</param>
        private IQueryable<ContentResource> AlternateQueryCondition(IQueryable<ContentResource> queryable)
        {
            var entity = _contentRepository.Find().OrderBy(t => t.PublicationTime).FirstOrDefault(t => t.State == ContentResourceState.Publish);
            if (entity == null)
                return queryable;
            return queryable.Where(t => t.PublicationTime > entity.PublicationTime);
        }

        #endregion

        /// <summary>
        /// 获取内容资源列表[输出]
        /// </summary>
        private List<ContentResourceListOutPut> GetResourceListOutPut(List<ContentResource> entities)
        {
            return entities.Select(t => t.ToNewsListOutPut(_commentRepository.Count(d => d.ContentResourceId == t.Id))).ToList();
        }

        /// <summary>
        /// 内容资源详情
        /// </summary>
        /// <param name="id">内容资源编号</param>
        public ContentResourceDetailOutPut Detail(Guid id)
        {
            var entity = _contentRepository.Find(id);
            return entity.ToNewsDetailOutPut();
        }
    }
}
